#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <dirent.h>
#include <limits.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <stdbool.h>
#include <errno.h>

// ====================== 配置常量 ======================
#define MAX_STACK_SIZE 20
#define MAX_PATH_LEN 4096
#define MAX_LS_BUFFER 16384
#define MAX_COMMAND_LEN 512
#define MAX_COMPONENTS 256

// ====================== 数据结构 ======================
typedef struct {
    char current_dir[MAX_PATH_LEN];   // 当前工作目录（相对根目录的绝对路径）
    char root_dir[MAX_PATH_LEN];      // 沙箱根目录（绝对路径）
    char *dir_stack[MAX_STACK_SIZE];  // 目录历史堆栈
    int stack_top;                    // 栈顶指针
} ClientSession;

// ====================== 辅助函数 ======================
// 安全字符串复制
void safe_strncpy(char *dest, const char *src, size_t n) {
    strncpy(dest, src, n-1);
    dest[n-1] = '\0';
}

// 确保路径以斜杠结尾
void ensure_trailing_slash(char *path) {
    size_t len = strlen(path);
    if (len > 0 && path[len-1] != '/' && len < MAX_PATH_LEN - 1) {
        strcat(path, "/");
    }
}

// ====================== 会话管理 ======================
// 初始化会话
void init_session(ClientSession *session, const char *root) {
    memset(session, 0, sizeof(ClientSession));
    
    // 处理根目录
    if (!root) root = "/tmp/default_root";
    
    // 获取真实路径
    char real_root[MAX_PATH_LEN];
    if (realpath(root, real_root)) {
        safe_strncpy(session->root_dir, real_root, MAX_PATH_LEN);
    } else {
        safe_strncpy(session->root_dir, root, MAX_PATH_LEN);
    }
    
    // 确保以'/'结尾
    ensure_trailing_slash(session->root_dir);
    
    // 设置当前目录为根目录
    safe_strncpy(session->current_dir, session->root_dir, MAX_PATH_LEN);
    
    session->stack_top = 0;
}

// 清理会话资源
void free_session(ClientSession *session) {
    for (int i = 0; i < session->stack_top; i++) {
        if (session->dir_stack[i]) {
            free(session->dir_stack[i]);
        }
    }
    session->stack_top = 0;
}

// ====================== 路径处理 ======================
// 路径规范化处理（修复版）
bool normalize_path(ClientSession *session, const char *input_path, char *output_path) {
    // 处理特殊路径
    if (strcmp(input_path, "~") == 0 || strcmp(input_path, "/") == 0) {
        safe_strncpy(output_path, session->root_dir, MAX_PATH_LEN);
        return true;
    }
    
    // 创建临时路径缓冲区
    char temp_path[MAX_PATH_LEN * 2] = {0};
    
    // 处理绝对路径
    if (input_path[0] == '/') {
        snprintf(temp_path, sizeof(temp_path), "%s%s", session->root_dir, input_path);
    } 
    // 处理相对路径
    else {
        snprintf(temp_path, sizeof(temp_path), "%s%s", session->current_dir, input_path);
    }
    
    // 使用realpath获取规范路径
    char resolved_path[MAX_PATH_LEN];
    if (!realpath(temp_path, resolved_path)) {
        return false;
    }
    
    // 确保路径在沙箱内
    if (strncmp(resolved_path, session->root_dir, strlen(session->root_dir)) != 0) {
        return false;
    }
    
    // 返回相对于根目录的路径
    const char *relative_path = resolved_path + strlen(session->root_dir);
    if (*relative_path == '\0') {
        strcpy(output_path, "/");
    } else {
        snprintf(output_path, MAX_PATH_LEN, "/%s", relative_path);
    }
    
    // 确保输出路径格式正确
    if (output_path[0] != '/') {
        char temp[MAX_PATH_LEN];
        snprintf(temp, sizeof(temp), "/%s", output_path);
        safe_strncpy(output_path, temp, MAX_PATH_LEN);
    }
    
    return true;
}

// ====================== 命令实现 ======================
// 压栈：保存当前目录
bool push_dir(ClientSession *session) {
    if (session->stack_top >= MAX_STACK_SIZE) {
        return false;
    }
    
    session->dir_stack[session->stack_top] = strdup(session->current_dir);
    if (!session->dir_stack[session->stack_top]) {
        return false;
    }
    
    session->stack_top++;
    return true;
}

// 弹栈：获取历史目录
char *pop_dir(ClientSession *session) {
    if (session->stack_top <= 0) {
        return NULL;
    }
    
    session->stack_top--;
    char *dir = session->dir_stack[session->stack_top];
    session->dir_stack[session->stack_top] = NULL;
    return dir;
}

// 处理cd命令（修复版）
bool handle_cd(ClientSession *session, const char *path) {
    if (!path || path[0] == '\0') {
        path = "~";
    }
    
    // 特殊命令：cd - (返回上一级)
    if (strcmp(path, "-") == 0) {
        if (session->stack_top == 0) {
            return false;
        }
        
        char *prev_dir = pop_dir(session);
        if (!prev_dir) return false;
        
        if (!push_dir(session)) {
            free(prev_dir);
            return false;
        }
        
        safe_strncpy(session->current_dir, prev_dir, MAX_PATH_LEN);
        free(prev_dir);
        return true;
    }
    
    char target[MAX_PATH_LEN] = {0};
    
    // 规范化路径
    if (!normalize_path(session, path, target)) {
        return false;
    }

    // 获取绝对路径
    char absolute_path[MAX_PATH_LEN];
    snprintf(absolute_path, sizeof(absolute_path), "%s%s", session->root_dir, target);
    
    // 验证路径存在
    struct stat st;
    if (stat(absolute_path, &st) != 0 || !S_ISDIR(st.st_mode)) {
        return false;
    }
    
    // 保存当前目录到堆栈
    if (!push_dir(session)) return false;
    
    // 更新当前目录（存储绝对路径）
    safe_strncpy(session->current_dir, absolute_path, MAX_PATH_LEN);
    ensure_trailing_slash(session->current_dir);
    
    return true;
}

// 处理pwd命令（修复版）
const char *handle_pwd(ClientSession *session) {
    static char result[MAX_PATH_LEN] = {0};
    
    // 获取相对于根目录的路径
    const char *relative = session->current_dir + strlen(session->root_dir);
    if (*relative == '\0') {
        strcpy(result, "/");
    } else {
        // 确保以斜杠开头
        if (relative[0] != '/') {
            snprintf(result, sizeof(result), "/%s", relative);
        } else {
            safe_strncpy(result, relative, MAX_PATH_LEN);
        }
    }
    
    // 移除尾部斜杠（根目录除外）
    size_t len = strlen(result);
    if (len > 1 && result[len-1] == '/') {
        result[len-1] = '\0';
    }
    
    return result;
}

// 处理ls命令（修复版）
char *handle_ls(ClientSession *session) {
    DIR *dir = opendir(session->current_dir);
    if (!dir) {
        return NULL;
    }

    char *result = (char *)calloc(MAX_LS_BUFFER, 1);
    if (!result) {
        closedir(dir);
        return NULL;
    }
    
    struct dirent *entry;
    while ((entry = readdir(dir)) != NULL) {
        if (entry->d_name[0] == '.') continue;
        
        char type = ' ';
        if (entry->d_type == DT_DIR) type = '/';
        else if (entry->d_type == DT_LNK) type = '@';
        
        char entry_str[256];
        snprintf(entry_str, sizeof(entry_str), "%-24s%c\n", entry->d_name, type);
        
        if (strlen(result) + strlen(entry_str) < MAX_LS_BUFFER - 1) {
            strcat(result, entry_str);
        }
    }
    closedir(dir);
    
    if (strlen(result) == 0) {
        strcpy(result, "No files or directories\n");
    }
    
    return result;
}

// 处理mkdir命令（修复版）
bool handle_mkdir(ClientSession *session, const char *path) {
    if (!path || path[0] == '\0') {
        return false;
    }
    
    char relative_path[MAX_PATH_LEN];
    if (!normalize_path(session, path, relative_path)) {
        return false;
    }
    
    // 构建绝对路径
    char absolute_path[MAX_PATH_LEN];
    snprintf(absolute_path, sizeof(absolute_path), "%s%s", session->root_dir, relative_path);
    
    // 移除尾部斜杠
    size_t len = strlen(absolute_path);
    if (len > 0 && absolute_path[len-1] == '/') {
        absolute_path[len-1] = '\0';
    }
    
    // 创建目录
    if (mkdir(absolute_path, 0700) != 0) {
        return false;
    }
    
    return true;
}

// 处理rmdir命令（修复版）
bool handle_rmdir(ClientSession *session, const char *path) {
    if (!path || path[0] == '\0') {
        return false;
    }
    
    char relative_path[MAX_PATH_LEN];
    if (!normalize_path(session, path, relative_path)) {
        return false;
    }
    
    // 构建绝对路径
    char absolute_path[MAX_PATH_LEN];
    snprintf(absolute_path, sizeof(absolute_path), "%s%s", session->root_dir, relative_path);
    
    // 移除尾部斜杠
    size_t len = strlen(absolute_path);
    if (len > 0 && absolute_path[len-1] == '/') {
        absolute_path[len-1] = '\0';
    }
    
    // 删除目录
    if (rmdir(absolute_path) != 0) {
        return false;
    }
    
    return true;
}

// ====================== 命令处理器 ======================
void process_command(ClientSession *session, const char *command) {
    if (!command) return;
    
    // 简化命令解析
    char cmd[32] = {0};
    char path[MAX_PATH_LEN] = {0};
    sscanf(command, "%31s %[^\n]", cmd, path);
    
    if (strcmp(cmd, "cd") == 0) {
        if (handle_cd(session, path)) {
            printf("CWD: %s\n", handle_pwd(session));
        } else {
            printf("ERROR: Directory change failed\n");
        }
    } 
    else if (strcmp(cmd, "pwd") == 0) {
        printf("Current directory: %s\n", handle_pwd(session));
    } 
    else if (strcmp(cmd, "ls") == 0) {
        char *list = handle_ls(session);
        if (list) {
            printf("%s", list);
            free(list);
        } else {
            printf("ERROR: Failed to list directory\n");
        }
    } 
    else if (strcmp(cmd, "mkdir") == 0) {
        if (handle_mkdir(session, path)) {
            printf("SUCCESS: Directory created\n");
        } else {
            printf("ERROR: Failed to create directory\n");
        }
    } 
    else if (strcmp(cmd, "rmdir") == 0) {
        if (handle_rmdir(session, path)) {
            printf("SUCCESS: Directory removed\n");
        } else {
            printf("ERROR: Failed to remove directory\n");
        }
    } 
    else {
        printf("ERROR: Unknown command '%s'\n", cmd);
    }
}

// ====================== 测试函数 ======================
int main() {
    const char *root_path = "/home/muridae/DraftsJ/TestsJ/Private_protocol_file_management_server_projectJ/PPFMSPJ/Tests1J/tmp/safe_root";
    
    ClientSession session;
    init_session(&session, root_path);
    
    printf("Root directory: %s\n", session.root_dir);
    printf("Current directory: %s\n", session.current_dir);
    
    // 创建测试环境
    mkdir(session.root_dir, 0700);
    chdir(session.root_dir);
    mkdir("documents", 0700);
    mkdir("projects", 0700);
    
    printf("\n=== Testing Commands ===\n");
    process_command(&session, "pwd");
    process_command(&session, "ls");
    process_command(&session, "cd documents");
    process_command(&session, "pwd");
    process_command(&session, "cd ..");
    process_command(&session, "pwd");
    process_command(&session, "mkdir new_folder");
    process_command(&session, "ls");
    process_command(&session, "rmdir new_folder");
    process_command(&session, "cd /");
    process_command(&session, "pwd");
    
    free_session(&session);
    return 0;
}
